#pragma once

#include <boost/preprocessor.hpp>

#ifndef CMAKE_UNITY_ID
    #define CMAKE_UNITY_ID
#endif

#define PP_CONCAT_IMPL(A, B) A##B
#define PP_CONCAT(A, B) PP_CONCAT_IMPL(A, B)
#define STR(x) #x
#if (CMAKE_UNITY_ID - CMAKE_UNITY_ID - 1 == 1)
    #define PTR_TMP_NAMESPACE
#else
    #define PTR_TMP_NAMESPACE PP_CONCAT(CMAKE_UNITY_ID, _)
#endif
#define PTR_TMP_STRING_NAME1(class) PP_CONCAT(__constexpr_char_, PP_CONCAT(class, _))
#define PTR_TMP_STRING_NAME2(class, property_name)                                                 \
    PP_CONCAT(PTR_TMP_STRING_NAME1(class), property_name)
#define PTR_TMP_STRING_NAME(class, property_name)                                                  \
    PP_CONCAT(PTR_TMP_NAMESPACE, PTR_TMP_STRING_NAME2(class, property_name))

#define PTR_TMP_STRING(class, property_name)                                                       \
    [[maybe_unused]] constexpr char PTR_TMP_STRING_NAME(class, property_name)[] =                  \
        STR(property_name);
#define SOLAR_GET_PTR(ptr, class, property_name)                                                   \
    auto ptr = solar::getParaPtr<class, PTR_TMP_STRING_NAME(class, property_name)>();
#define SOLAR_SET_VALUE(class, property_name, property, object)                                    \
    object.*solar::getParaPtr<class, PTR_TMP_STRING_NAME(class, property_name)>() = property;
#define SOLAR_GET_VALUE(class, property_name, object)                                              \
    object.*solar::getParaPtr<class, PTR_TMP_STRING_NAME(class, property_name)>()
#define SOLAR_SET_VALUE2(namespace, class, property_name, property, object)                                    \
    object.*solar::getParaPtr<namespace::class, PTR_TMP_STRING_NAME(class, property_name)>() = property;
#define SOLAR_GET_VALUE2(namespace, class, property_name, object)                                              \
    object.*solar::getParaPtr<namespace::class, PTR_TMP_STRING_NAME(class, property_name)>()

// 计算 __VA_ARGS__ 参数个数,最大支持64个参数
#define FL_INTERNAL_ARG_COUNT_PRIVATE(                                                             \
    _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
    _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, \
    _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, \
    _59, _60, _61, _62, _63, _64, N, ...)                                                          \
    N
#define FL_ARG_COUNT(...)                                                                          \
    FL_INTERNAL_ARG_COUNT_PRIVATE(                                                                 \
        0, ##__VA_ARGS__, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47,  \
        46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25,    \
        24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

#define MACRO(r, data, elem) PTR_TMP_STRING(data, elem)
#define PP_UNPACK(...) (FL_ARG_COUNT(__VA_ARGS__), (__VA_ARGS__))
#define LIST(...) BOOST_PP_ARRAY_TO_LIST(PP_UNPACK(__VA_ARGS__))
#define SOLAR_PP_UNPACK(...) , ##__VA_ARGS__
#define SOLAR_DESCRIBE_CLASS(C, Bases, Public, Protected, Private)                                 \
    BOOST_PP_LIST_FOR_EACH(MACRO, C, LIST(SOLAR_PP_UNPACK Public))                                 \
    BOOST_PP_LIST_FOR_EACH(MACRO, C, LIST(SOLAR_PP_UNPACK Protected))                              \
    BOOST_PP_LIST_FOR_EACH(MACRO, C, LIST(SOLAR_PP_UNPACK Private))
